package com.longxiao.service.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Created by houhongwei on 2017/5/2.
 */
@Service("redisClient")
public class RedisClient {

    @Autowired
    RedisTemplate redisTemplate;


    public final byte[] serialize(String value) {
        RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
        return serializer.serialize(value);
    }

    public final String deserialize(byte[] value) {
        RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
        return serializer.deserialize(value);
    }



    public void set(final String key, final String value) {
        redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                byte[] tmpKey  = serialize(key);
                byte[] tmpValue = serialize(value);
                redisConnection.set(tmpKey, tmpValue);
                return Boolean.TRUE;
            }
        });
    }

    public void setEx(final String key, final String value, final int seconds) {
        redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                byte[] tmpKey = serialize(key);
                byte[] tmpValue = serialize(value);
                redisConnection.setEx(tmpKey, seconds, tmpValue);
                return Boolean.TRUE;
            }
        });
    }

    public Boolean setNx(final String key, final String value) {
        Boolean bool = (Boolean) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                byte[] tmpKey = serialize(key);
                byte[] tmpValue = serialize(value);
                Boolean bool = redisConnection.setNX(tmpKey, tmpValue);
                return bool;
            }
        });
        return bool;
    }

    public boolean expire(final String key, final int seconds) {
        Boolean bool = (Boolean) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                byte[] tmpKey = serialize(key);
                return redisConnection.expire(tmpKey, seconds);
            }
        });
        return bool;
    }

    public boolean expireAt(final String key, final long time) {
        Boolean bool = (Boolean) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                byte[] tmpKey = serialize(key);
                return redisConnection.expireAt(tmpKey, time);
            }
        });
        return bool;
    }


    public boolean exists(final String key) {
        Boolean bool = (Boolean) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                byte[] tmpKey = serialize(key);
                return redisConnection.exists(tmpKey);
            }
        });
        return bool;
    }

    public String get(final String key) {
        String result = (String) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                return deserialize(redisConnection.get(serialize(key)));
            }
        });
        return result;
    }

    public Long incr(final String key) {
        Long result = (Long) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                return redisConnection.incr(serialize(key));
            }
        });
        return result;
    }



    // ========================================================================================================================= //
    // set
    public Long sadd(final String key, final String value) {
        Long result = (Long) redisTemplate.execute(new RedisCallback() {
                @Override
                public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                byte[] tmpKey = serialize(key);
                byte[] tmpValue = serialize(value);
                Long l = redisConnection.sAdd(tmpKey, tmpValue);
                return l;
            }
        });
        return result;
    }

    public Long scard (final String key) {
        Long result = (Long) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                byte[]tmpKey = serialize(key);
                Long l = redisConnection.sCard(tmpKey);
                return l;
            }
        });
        return result;
    }

    public Set<String> sdiff(final String key1, final String key2) {
        Set<String> result = (Set<String>) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                byte[] tmpKey1 = serialize(key1);
                byte[] tmpKey2 = serialize(key2);
                Set<byte[]> result = redisConnection.sDiff(tmpKey1, tmpKey2);
                Set<String> set = new HashSet<String>();
                for (byte[] b : result) {
                    set.add(deserialize(b));
                }
                return set;
            }
        });
        return result;
    }


    public Long sdiffStore(final String key1, final String key2, final String destKey) {
        Long result = (Long) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                byte[] tmpKey1 = serialize(key1);
                byte[] tmpKey2 = serialize(key2);
                byte[] tmpDestKey = serialize(destKey);
                Long l = redisConnection.sDiffStore(tmpDestKey, tmpKey1, tmpKey2);
                return l;
            }
        });
        return result;
    }


    public Long srem(final String key, final String value) {
        Long result = (Long) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                byte[] tmpKey = serialize(key);
                byte[] tmpValue = serialize(value);
                Long l = redisConnection.sRem(tmpKey, tmpValue);
                return l;
            }
        });
        return result;
    }


    public String spop(final String key) {
        String result = (String) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                byte[] tmpKey = serialize(key);
                byte[] b = redisConnection.sPop(tmpKey);
                return deserialize(b);
            }
        });
        return result;
    }

    public boolean smember(final String key, final String value) {
        boolean result = (Boolean) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                return redisConnection.sIsMember(serialize(key), serialize(value));
            }
        });
        return result;
    }

    // set end
    // ========================================================================================================================= //
    
    public Long lPush(final String key,final String value) {
    	 Long result = (Long) redisTemplate.execute(new RedisCallback() {
             @Override
             public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                 return redisConnection.lPush(serialize(key), serialize(value));
             }
         });
         return result;
    }
    
    public String lpop(final String key) {
        String result = (String) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                byte[] tmpKey = serialize(key);
                byte[] b = redisConnection.lPop(tmpKey);
                return deserialize(b);
            }
        });
        return result;
    }
}
